/*	
 * Authors: Ken YANG <spng.yang@gmail.com>
 * 	
 * Introduction
 * Implementation of mmh_client_open(), see details below
 *
 * Copyright (C) 2007-2008 Ken YANG
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation, version 2. 
 * THIS SOFTWARE COMES "AS IS" WITHOUT ANY WARRANTIES.
 */

#include "mmh.h"


/*
 * Name: mmh_client_open()
 *
 * Description:
 * Take care of client stuffs before sending data, including 
 * create socket, set socket options, bind, connect and 
 * etc...
 *
 * FIXME:
 * My aim is to be independent of IPv4 and IPv6, but still 
 * had not test environment
 *
 * Parameters:
 * host: 	remote server, hostname or ip addr representation
 * service:	service or port number
 *
 * Return Values:
 * The client socket 
 *
 * */
int 
mmh_client_open(char *host,char *service)
{
	int client_sockfd, rc;
	struct addrinfo hint, *result, *index;

	bzero(&hint,sizeof(struct addrinfo));
	hint.ai_socktype=mmh_udp_f ? SOCK_DGRAM : SOCK_STREAM;
	hint.ai_family=AF_UNSPEC;

	if((rc=getaddrinfo(host,service,&hint,&result))!=0)
		err_quit(gai_strerror(rc));

	index=result;
	do{
		/* socket error here isnt fatal */
		client_sockfd=socket(index->ai_family,
				mmh_udp_f?SOCK_DGRAM:SOCK_STREAM,0);
		if(client_sockfd<0) continue;	/* error, try next one */

		Setsockopt(serv_sockfd,SOL_SOCKET,SO_REUSEADDR,1,sizeof(int));
#ifdef SO_REUSEPORT
		Setsockopt(serv_sockfd,SOL_SOCKET,SO_REUSEPORT,1,sizeof(int));
#endif
		/* 
		 * For UDP, we "bind" ephemeral port to socket, and 
		 * TCP not, except that user require. 
		 *
		 * Can be "wildcard", if port and localip are both 
		 * empty.
		 * */
		if(mmh_bindport!=0 || mmh_localaddr[0]!=0 || mmh_udp_f){
			bzero(&mmh_cliaddr,sizeof(mmh_cliaddr));
			mmh_cliaddr.sin_family=index->ai_family;
			mmh_cliaddr.sin_port=htons(mmh_bindport);
			if(mmh_localaddr[0]!=0){
				if(inet_pton(index->ai_family,
						mmh_localaddr,
						&mmh_cliaddr.sin_addr)==0)
					err_quit("invalid IP address: %s",
							mmh_localaddr);
			}else
				/* wildcard */
				mmh_cliaddr.sin_addr.s_addr=htonl(INADDR_ANY);
			Bind(client_sockfd,(SA)&mmh_cliaddr,sizeof(mmh_cliaddr)); 
		}
		/* 
		 * Allocate buffers before connect, because they will 
		 * affect some TCP options, such as Windows Size, and etc
		 * */
		mmh_buffers_alloc(client_sockfd);
		mmh_sockopts(client_sockfd, 0);

		/* 
		 * connect to the server, required for TCP, optional 
		 * for UDP.
		 * */
		if(mmh_udp_f==0 || mmh_udpconnect){
			/* TODO */
			connect();
		}
	}while((index=index->ai_next)!=NULL);
}


